﻿using System;
using System.Collections.Generic;

namespace TradeClient.Logic.TradeCore
{
    /// <summary>
    /// 表示特定K线序列的类
    /// </summary>
    public class KLineSeries
    {
        /// <summary>
        /// K线唯一ID
        /// </summary>
        public string Id { get; private set; }

        /// <summary>
        /// 所属交易市场
        /// </summary>
        public MarketType Market { get; private set; }

        /// <summary>
        /// K线代码（股票代码，期货合约代码等）
        /// </summary>
        public string Code { get; private set; }

        /// <summary>
        /// K线级别（例如：分钟或天）
        /// </summary>
        public int Level { get; private set; }

        /// <summary>
        /// K线单位（分钟线，日线等）
        /// </summary>
        public KLineUnitType Unit { get; private set; }

        /// <summary>
        /// K线序列
        /// </summary>
        public List<KLine> Series { get; set; }


        /// <summary>
        /// K线更新事件
        /// </summary>
        public event PriceUpdateDelegate PriceUpdate;
        public delegate void PriceUpdateDelegate(KLineSeries series);

        /// <summary>
        /// K线完成事件
        /// </summary>
        public event KLineFinishedDelegate KLineFinished;
        public delegate void KLineFinishedDelegate(KLineSeries series);

        /// <summary>
        /// K线新开事件
        /// </summary>
        public event KLineOpenDelegate KLineOpen;
        public delegate void KLineOpenDelegate(KLineSeries series);


        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="code">代码</param>
        /// <param name="level">K线级别</param>
        /// <param name="unit">K线单位</param>
        /// <param name="size">容量</param>
        public KLineSeries(MarketType market, string code, int level, KLineUnitType unit, int size = 240)
        {
            this.Market = market;
            this.Code = code;
            this.Level = level;
            this.Unit = unit;

            this.Series = new List<KLine>(size);
            this.Id = market.ToString() + "_" + code + "_" + level.ToString();
        }

        /// <summary>
        /// 将一根新K线加入序列
        /// </summary>
        /// <param name="kLine">K线</param>
        public void Add(KLine kLine)
        {
            this.Series.Add(kLine);
        }

        /// <summary>
        /// 将一根新K线加入序列
        /// </summary>
        /// <param name="openTime">K线开始时间</param>
        /// <param name="price">开盘价</param>
        public void Add(DateTime openTime, double price)
        {
            KLine k = new KLine(openTime, price);

            this.Add(k);
        }

        public void Insert()
        {

        }

        public void Remove()
        {

        }

        /// <summary>
        /// 获取指定索引的K线（最新的一根的索引为零,如果不存在则为空）
        /// </summary>
        public KLine this[int index]
        {
            get
            {
                KLine k     = null;
                int count   = Series.Count - 1;

                if (0 <= index && index <= count)
                    k = Series[count - index];

                return k;
            }
        }

        /// <summary>
        /// 价格更新事件处理
        /// </summary>
        /// <param name="price">最新价格</param>
        public void UpdatePrice(QuoteData queueQuoteData)
        {
            if (this[0] == null)
            {
                this.Add(queueQuoteData.UpdateTime, queueQuoteData.Price);
            }
            else
            {
                double span = 0;
                TimeSpan timeSpan = queueQuoteData.UpdateTime - this[0].OpenTime;

                if (this.Unit == KLineUnitType.Minutes)
                    span = timeSpan.TotalMinutes;
                else
                    span = timeSpan.TotalDays;

                if (span > this.Level)
                {
                    //引发K线完成事件
                    if( KLineFinished != null ) KLineFinished(this);

                    //加入新的K线
                    this.Add(queueQuoteData.UpdateTime, queueQuoteData.Price);

                    //引发K线新开事件
                    if (KLineOpen != null) KLineOpen(this);
                }
            }

            //更新K线收盘价
            this[0].UpdatePrice(queueQuoteData.Price);

            //引发价格更新事件
            if (PriceUpdate != null) PriceUpdate(this);
        }

        /// <summary>
        /// 注册策略类的K线事件
        /// </summary>
        /// <param name="policy">策略类实例</param>
        public void RegPolicy(PolicyBase policy)
        {
            this.PriceUpdate    += policy.PriceUpdate;
            this.KLineFinished  += policy.KLineFinished;
            this.KLineOpen      += policy.KLineOpen;
        }
    }
}
